package com.py.credit.service.excel.read;

import com.py.credit.entity.Column;
import com.py.credit.entity.common.InspectRule;
import com.py.credit.service.excel.read.service.impl.TimeDataFormat;
import com.py.credit.utils.DateUtil;
import com.py.credit.utils.MD5Util;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据校验功能工具类
 *
 * @author YaoS
 * @date 2019-04-03 09:57
 */
public class InspectHandles {
	public static final String SINGLE_QUOTATION = "\'";

	public static final String TYPE_TIMESTAMP = "timestamp";

	public static final String TYPE_NUMBER = "number";
	/**
	 * 数值类型校验
	 */
	public static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]+([.]{1}[0-9]{1,2})?$");
	/**
	 * 数值类型校验（六位小数）
	 */
	public static final Pattern NUMBER_PATTERN_DOUBLE_PUBLICITY = Pattern.compile("^[0-9]+([.]{1}[0-9]{1,6})?$");
	/**
	 * 时间类型校验
	 */
	public static final Pattern DATE_PATTERN = Pattern.compile(
			"(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)");

	/**
	 * 功能描述: Timestamp字段值转为String类型
	 *
	 * @param column 待转换字段信息
	 * @param map    待转换数据
	 * @return 转换结果
	 * @author YaoS`
	 * @date 19/3/29 14:44
	 */
	public static String dateToStr(Column column, Map<String, Object> map) {
		String dataValue;
		if (map.get(column.getMetricCode()) instanceof Timestamp) {
			dataValue = DateUtil.getInstance().dateToStr(((Timestamp) map.get(column.getMetricCode())),
					DateUtil.YYYY__MM__DD);
		} else {
			dataValue = (String) map.get(column.getMetricCode());
		}
		return dataValue;
	}

	/**
	 * 功能描述: 字段规则校验
	 *
	 * @param isr       规则对象
	 * @param dataValue 校验的数据
	 * @return 校验结果
	 * @author YaoS
	 * @date 19/3/29 11:38
	 */
	public static boolean ruleCheckForColumn(InspectRule isr, String dataValue) throws Exception {
		Class<?> c = Class.forName(isr.getRulePackage());
		Method m = c.getMethod(isr.getRuleMethod(), String.class, String.class);
		return (boolean) m.invoke(c.newInstance(), dataValue, isr.getExtend());
	}

	/**
	 * 功能描述: 表规则校验
	 *
	 * @param isr 规则对象
	 * @param map 校验的数据
	 * @return 校验结果
	 * @author YaoS
	 * @date 19/3/29 11:38
	 */
	public static boolean ruleCheckForTable(InspectRule isr, Map<String, Object> map) throws Exception {
		Class<?> c = Class.forName(isr.getRulePackage());
		Method m = c.getMethod(isr.getRuleMethod(), Map.class, String.class);
		return (boolean) m.invoke(c.newInstance(), map, isr.getExtend());
	}

	/**
	 * 功能描述: 对字段生成空值时的MD5
	 *
	 * @param columns 字段的List
	 * @return MD5
	 * @author YaoS
	 * @date 19/3/29 9:51
	 */
	public static String calcMD5byColumn(List<Column> columns) {
		StringBuilder enptyData = new StringBuilder();
		// 对字段循环拼接
		for (Column column : columns) {
			enptyData.append(column.getMetricCode()).append("|");
		}
		return MD5Util.getInstance().md5s(enptyData.toString().getBytes());
	}

	/**
	 * 功能描述:拼接字段名和值进行MD5计算
	 *
	 * @param columns 校验字段
	 * @param dataMap 校验数据Map
	 * @return MD5
	 * @author YaoS
	 * @date 19/3/29 11:19
	 */
	public static String calcMD5(List<Column> columns, Map<String, Object> dataMap) {
		StringBuilder data = new StringBuilder();
		// 每一列的值进行组装
		for (Column column : columns) {
			// 用字段名称做首填充，防止出现 像 1null2 12null 生成的MD5值相同造成认为是重复数据
			String value;
			if (null != dataMap.get(column.getMetricCode())) {
				value = String.valueOf(dataMap.get(column.getMetricCode()));
			} else {
				value = "";
			}
			data.append(column.getMetricCode()).append("|");
			data.append(StringUtils.isBlank(value) ? "" : value);
		}
		// 进行MD5计算
		return MD5Util.getInstance().md5s(data.toString().getBytes());
	}

	/**
	 * 功能描述: 单条数据库规则校验
	 *
	 * @param map            待校验数据
	 * @param columns        列信息
	 * @param timeDataFormat 时间校验格式化
	 * @return 校验结果
	 * @author YaoS
	 * @param tableId
	 * @date 19/3/29 17:16
	 */
	public static String singleDataFormatCheck(Map<String, Object> map, List<Column> columns,
			TimeDataFormat timeDataFormat, int tableId) {
		// 第一步的数据重复校验已判空，不需要进行非空校验
		StringBuilder error = new StringBuilder();
		for (Column column : columns) {
			String code = column.getMetricCode();
			// 没有值跳过校验
			if (null == map.get(code) || StringUtils.isBlank(String.valueOf(map.get(code)))) {
				continue;
			}
			String value = String.valueOf(map.get(code));
			String name = column.getMetricName();
			String type = column.getFieldType();
			if (InspectHandles.TYPE_TIMESTAMP.equals(type)) {
				String extend=  "((\\d{2}(([02468][048])|([13579][26]))[\\-]((((0?[13578])|(1[02]))[\\-]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-]((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-]((((0?[13578])|(1[02]))[\\-]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-]((0?[1-9])|(1[0-9])|(2[0-8]))))))";
                // 时间类型不匹配
            	Pattern p = Pattern.compile(extend);
                Matcher m = p.matcher(value.replace("/", "-"));
                boolean dateFlag = m.matches();
                if(!dateFlag){
                	 error.append("字段" + name + "类型不匹配，应为时间类型;");
                }
			} else if (InspectHandles.TYPE_NUMBER.equals(type)) {
				if (210000 == tableId || 210001 == tableId || 210002 == tableId || 210003 == tableId) {
					//  自然人行政处罚和法人行政处罚数值类型的字段，要求小数点必须为6位
					Matcher m = InspectHandles.NUMBER_PATTERN_DOUBLE_PUBLICITY.matcher(value);
					if (!m.matches()) {
						error.append("字段" + name + "类型不匹配，应为最多六位小数的数值类型;");
					}
				}
//				else {
//					// 数值类型不匹配
//					Matcher m = InspectHandles.NUMBER_PATTERN.matcher(value);
//					if (!m.matches()) {
//						error.append("字段" + name + "类型不匹配，应为最多两位小数的数值类型;");
//					}
//				}
			} else {
				int length = column.getFieldLength();
				// 字段长度超长
				if (value.length() > length) {
					error.append("字段" + name + "长度超过数据表长度;");
				}
			}
		}
		return error.toString();
	}
}
